package org.study.bookmanager.service.impl;

import jakarta.annotation.Resource;
import jakarta.persistence.criteria.Predicate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.study.bookmanager.entity.*;
import org.study.bookmanager.io.reponse.RestBean;
import org.study.bookmanager.io.request.Book.AddBookReq;
import org.study.bookmanager.io.request.Book.AddBookTypeReq;
import org.study.bookmanager.io.request.Book.GetBooksReq;
import org.study.bookmanager.io.request.Book.UpdateBookReq;
import org.study.bookmanager.repo.BarcodesRespsitory;
import org.study.bookmanager.repo.BooksRespository;
import org.study.bookmanager.repo.BorrowsRespository;
import org.study.bookmanager.repo.ReservationRespository;
import org.study.bookmanager.service.BookService;
import org.study.bookmanager.utils.CopyUtils;
import org.study.bookmanager.utils.DateUtils;
import org.springframework.data.domain.Pageable;//???
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Service
public class BookServiceImpl implements BookService {

    @Resource
    BooksRespository booksRespository;

    @Resource
    BarcodesRespsitory barcodesRespsitory;

    @Resource
    ReservationRespository reservationRespository;

    @Resource
    BorrowsRespository borrowsRespository;

    @Value("${book-manager.default.duedate}")
    int dueDate;
    /**
     * @param req
     * @return
     */
    @Override
    public Object addBookType(AddBookTypeReq req) {
        if(booksRespository.existsByIsbn(req.getIsbn())){
            return RestBean.Code.图书信息已存在;
        }
        List<BookCategory>bookCategories=new ArrayList<>();
        for(String category:req.getCategorys()){
            BookCategory bookCategory=new BookCategory();
            bookCategory.setCategoryName(category);
            bookCategories.add(bookCategory);
        }
        Books book = Books.builder().
                categories(bookCategories).
                isbn(req.getIsbn()).
                title(req.getTitle()).
                author(req.getAuthor()).
                publisher(req.getPublisher()).
                publicationYear(req.getPublication_year()).
                price(req.getPrice()).build();
        booksRespository.save(book);
        return book.getBookId();
    }

    /**
     * @param req
     * @return
     */
    @Override
    public Object addBook(AddBookReq req) {
        if(!booksRespository.existsByIsbn(req.getIsbn())){
            return RestBean.Code.图书信息不存在;
        }
        Books book=booksRespository.findByIsbn(req.getIsbn());
        List<Reservation> reservations = reservationRespository.findByBookAndFinishFalseOrderByReservedDateAsc(book);
        Barcodes barcode=Barcodes.builder().
                book(book).
                barcode(req.getBarcodes()).build();
        if (!reservations.isEmpty()) {
            Reservation earliestReservation = reservations.get(0);
            earliestReservation.setFinish(true);
            reservationRespository.save(earliestReservation);
            barcode.setStatus(Barcodes.Status.BORROWED_OUT);
            Borrows borrow=Borrows.builder().
                    users(earliestReservation.getUser()).
                    books(book).
                    dueDate(DateUtils.addDays(new Date(),dueDate)).build();
            borrowsRespository.save(borrow);
        }else{
            book.setAvailableToBorrow(book.getAvailableToBorrow()+1);
        }
        book.setStockQuantity(book.getStockQuantity()+1);
        barcodesRespsitory.save(barcode);
        booksRespository.save(book);
        return RestBean.ok;
    }

    /**
     * @param barcodeId
     * @return
     */
    @Override
    public Object deleteBook(int barcodeId) {
        barcodesRespsitory.deleteById(barcodeId);
        return RestBean.ok;
    }

    /**
     * @param req
     * @return
     */
    @Override
    public Object updateBook(UpdateBookReq req) {
        if(!booksRespository.existsByIsbn(req.getIsbn())){
            return RestBean.Code.图书信息不存在;
        }
        List<BookCategory>bookCategories=new ArrayList<>();
        for(String category:req.getCategorys()){
            BookCategory bookCategory=new BookCategory();
            bookCategory.setCategoryName(category);
            bookCategories.add(bookCategory);
        }
        Books bookReq=Books.builder().
                categories(bookCategories).
                isbn(req.getIsbn()).
                title(req.getTitle()).
                author(req.getAuthor()).
                publisher(req.getPublisher()).
                price(req.getPrice()).
                stockQuantity(req.getStock_quantity()).
                availableToBorrow(req.getAvailable_to_borrow()).
                publicationYear(req.getPublication_year()).build();
        Books book=booksRespository.findByIsbn(req.getIsbn());
        CopyUtils.copyProperties(bookReq,book);
        booksRespository.save(book);
        return book.getBookId();
    }

    /**
     * @param req
     * @return
     */
    @Override
    public Object findBooks(GetBooksReq req) {
        Specification<Books> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (req.getId() != null) {
                predicates.add(criteriaBuilder.equal(root.get("bookId"), req.getId()));
            }
            if (req.getTitle() != null) {
                predicates.add(criteriaBuilder.like(root.get("title"), "%" + req.getTitle() + "%"));
            }
            if (req.getAuthor() != null) {
                predicates.add(criteriaBuilder.like(root.get("author"), "%" + req.getAuthor() + "%"));
            }
            if (req.getPublisher() != null) {
                predicates.add(criteriaBuilder.like(root.get("publisher"), "%" + req.getPublisher() + "%"));
            }
            if (req.getIsbn() != null) {
                predicates.add(criteriaBuilder.equal(root.get("isbn"), req.getIsbn()));
            }
            if (req.getCategorys() != null && !req.getCategorys().isEmpty()) {
                predicates.add(root.join("categories").get("categoryName").in(req.getCategorys()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };

        Pageable pageable = PageRequest.of(req.getPageReq().getPage(), req.getPageReq().getLimit());//这里需要注意还有个awt.print.pageable，不要弄混了

        return booksRespository.findAll(specification, pageable);
    }
}
